home *** CD-ROM | disk | FTP | other *** search
- /* driver.c */
-
- /*
- * The following code is to install and remove RAM drivers in the system
- * heap. Written by Pete Resnick with the help of Joe Holt, Phil Shapiro,
- * Tom Johnson, Michael A. Libes, Matthias Urlichs, John Norstad, and
- * Charles Martin.
- *
- * Change Log
- * ----------
- * Date: Change: Who:
- * ----- ------- ----
- * 22 Jan 91 Changed "if (UTableSize < UnitNtryCnt) {" pr
- * to "if (UTableSize > UnitNtryCnt) {" in
- * DriverAvail.
- *
- * 28 Jan 91 Make sure resource map is updated to pr
- * change back the resource ID's in
- * InstallRAMDriver by adding code to
- * SetResFileAttrs and UpdateResFile.
- */
-
- #include <MacTypes.h>
- #include <DeviceMgr.h>
- #include <FileMgr.h>
- #include <MemoryMgr.h>
- #include <ResourceMgr.h>
- #include "driver.h"
-
- #define LOW_UNIT 48 /* First Unit Table Entry to use */
- #define NEW_UNIT 64 /* Size of a "normal" Unit Table */
- #define MAX_UNIT 128 /* Maximum size of a Unit Table */
- #define UP_UNIT 4 /* Size to bounce up Unit Table */
- #define nil 0L /* Just nil */
- #define SCCLockOut 0x2600 /* Disable interrupts flag */
-
- pascal OSErr DrvrInstall(Handle drvrHandle, short refNum)
- {
- asm {
- MOVE.W refNum, D0 ; driver reference number
- MOVEA.L drvrHandle, A0 ; handle to driver
- MOVEA.L (A0), A0 ; pointer to driver
- DC.W 0xA03D ; _DrvrInstall
- ; error is in DO (and is pushed on stack)
- }
- }
-
- pascal OSErr DrvrRemove(short refNum)
- {
- asm {
- MOVE.W refNum, D0 ; driver reference number
- DC.W 0xA03E ; _DrvrRemove
- ; error is in DO (and is pushed on stack)
- }
- }
-
- /*
- * InstallRAMDriver will install the named driver into the system heap
- * locked and return the driver reference number in refNum. Make sure
- * that the DRVR resources are numbered between 0 and 47 and that the
- * resources owned by the driver are also numbered appropriately. Using
- * resource ID's of 48 and higher may cause conflicts if you are using
- * the THINK C global data DATA resource or the THINK C multi-segment
- * DCOD resource, which get temporarily renumbered by this routine.
- * One major kludge: the ioMisc field of the ioParam block is not used
- * for non-file operations, so it is used to store a pointer to a block
- * containing the addresses of the DCOD resources (if they are being
- * used) so that they can be removed by RemoveRAMDriver. If Apple ever
- * uses that field, that mechanism will be gone. See driver.h for the
- * drvrInstFlags.
- */
-
- OSErr InstallRAMDriver(Str255 drvrName, short *refNum, Byte drvrInstFlags)
- {
- OSErr errCode;
- short index, rsrcID, dcodRsrcID, unitNum, dcodSegments, dcodIndex;
- ResType rsrcType;
- Str255 rsrcName;
- Handle dataHandle, drvrHandle, *dcodHList = nil, tempHandle;
- ioParam openBlock;
- register DriverPtr drvrPtr;
- register DCtlPtr ctlEntryPtr;
-
- /* Get the unit number for the driver */
- errCode = DriverAvail(&unitNum);
- if(errCode != noErr)
- return(errCode);
-
- /* The driver must load into the system heap locked. */
- SetResLoad(false);
- drvrHandle = Get1NamedResource('DRVR', drvrName);
- SetResLoad(true);
- if(drvrHandle == nil)
- return(dInstErr);
- SetResAttrs(drvrHandle, resSysHeap + resLocked);
- if(ResErr != noErr) {
- errCode = ResErr;
- ReleaseResource(drvrHandle);
- return(errCode);
- }
-
- /* Save the resource info for later use */
- GetResInfo(drvrHandle, &rsrcID, &rsrcType, &rsrcName);
- if(ResErr != noErr) {
- errCode = ResErr;
- ReleaseResource(drvrHandle);
- return(errCode);
- }
-
- /* Now load it and detach it */
- LoadResource(drvrHandle);
- if(ResErr != noErr) {
- errCode = ResErr;
- ReleaseResource(drvrHandle);
- return(errCode);
- }
- DetachResource(drvrHandle);
-
- if(drvrInstFlags & thinkDATA) {
- /*
- * Make sure the DATA resource will load into the system heap,
- * locked, and is owned by our driver, where the ID is the
- * unitNum in bits 5 through 10 (or 11 if needed), zeros in
- * bits 11 (if there is room) 12 and 13 (which means DRVR), zeros
- * in bits 0 through 4 (since there is only 1 DATA resource), and
- * ones in bits 14 and 15. If any errors occur after the resource
- * ID is changed, it must be changed back!
- */
- SetResLoad(false);
- dataHandle = Get1Resource('DATA', (rsrcID << 5) | 0xC000);
- SetResLoad(true);
- if(dataHandle == nil) {
- errCode = ResErr;
- DisposHandle(drvrHandle);
- return(errCode != noErr ? errCode : resNotFound);
- }
- SetResAttrs(dataHandle, resSysHeap + resLocked);
- if(ResErr != noErr) {
- errCode = ResErr;
- DisposHandle(drvrHandle);
- return(errCode);
- }
- SetResInfo(dataHandle, (unitNum << 5) | 0xC000, 0);
- if(ResErr != noErr) {
- errCode = ResErr;
- DisposHandle(drvrHandle);
- return(errCode);
- }
- }
-
- if(drvrInstFlags & thinkMultSeg) {
- /*
- * Make sure the DCOD resources will load into the system heap,
- * locked, and are owned by our driver, where the ID is the
- * unitNum in bits 5 through 10 (or 11 if needed), zeros in
- * bits 11 (if there is room) 12 and 13 (which means DRVR),
- * the same ID in bits 0 through 4, and ones in bits 14 and 15.
- * Keep a block containing the handles to those segments so that
- * they can be thrown away later if needed. If any errors
- * occur after the resource ID's are changed, they are changed
- * back in ReleaseDrvrSegments.
- */
- dcodSegments = 0;
- errCode = noErr;
- SetResLoad(false);
-
- /* Count how many segments there are */
- for(index = 1;
- (index <= Count1Resources('DCOD')) && (errCode == noErr);
- ++index) {
- tempHandle = Get1IndResource('DCOD', index);
- if(tempHandle == nil)
- errCode = (ResErr != noErr ? ResErr : resNotFound);
- GetResInfo(tempHandle, &dcodRsrcID, &rsrcType, &rsrcName);
- ReleaseResource(tempHandle);
- if((dcodRsrcID & ~0xF01F) >> 5 == rsrcID)
- ++dcodSegments;
- }
- SetResLoad(true);
-
- if(errCode != noErr) {
- if(drvrInstFlags & thinkDATA) {
- SetResInfo(dataHandle, (rsrcID << 5) | 0xC000, 0);
- SetResFileAttrs(CurResFile(),
- GetResFileAttrs(index) | mapChanged);
- UpdateResFile(CurResFile());
- ReleaseResource(dataHandle);
- }
- DisposHandle(drvrHandle);
- return(errCode);
- }
-
- /* Get a block of memory to hold the handles */
- dcodHList = (Handle *)NewPtrSysClear(sizeof(Handle) * dcodSegments);
- if(dcodHList == nil) {
- if(drvrInstFlags & thinkDATA) {
- SetResInfo(dataHandle, (rsrcID << 5) | 0xC000, 0);
- SetResFileAttrs(CurResFile(),
- GetResFileAttrs(index) | mapChanged);
- UpdateResFile(CurResFile());
- ReleaseResource(dataHandle);
- }
- DisposHandle(drvrHandle);
- return(memFullErr);
- }
-
- /* Get the resources and change the attributes and ID's */
- dcodIndex = 0;
- SetResLoad(false);
- for(index = 1;
- (index <= Count1Resources('DCOD')) && (errCode == noErr);
- ++index) {
- tempHandle = Get1IndResource('DCOD', index);
- if(tempHandle == nil) {
- errCode = (ResErr != noErr ? ResErr : resNotFound);
- } else {
- GetResInfo(tempHandle, &dcodRsrcID, &rsrcType, &rsrcName);
- if((dcodRsrcID & ~0xF01F) >> 5 == rsrcID) {
- dcodHList[dcodIndex] = tempHandle;
- SetResAttrs(dcodHList[dcodIndex],
- resSysHeap + resLocked);
- if(ResErr != noErr) {
- errCode = ResErr;
- } else {
- SetResInfo(dcodHList[dcodIndex],
- (dcodRsrcID & 0xF01F) + (unitNum << 5),
- 0);
- errCode = ResErr;
- }
- ++dcodIndex;
- }
- }
- }
- SetResLoad(true);
-
- if(errCode != noErr) {
- if(drvrInstFlags & thinkDATA) {
- SetResInfo(dataHandle, (rsrcID << 5) | 0xC000, 0);
- ReleaseResource(dataHandle);
- }
- ReleaseDrvrSegments(dcodHList, rsrcID, false);
- DisposHandle(drvrHandle);
- return(dInstErr);
- }
- }
-
- /* Install with the refNum. The refNum is the -(unitNum + 1) */
- errCode = DrvrInstall(drvrHandle, ~unitNum);
- if(errCode != noErr) {
- if(drvrInstFlags & thinkDATA) {
- SetResInfo(dataHandle, (rsrcID << 5) | 0xC000, 0);
- SetResFileAttrs(CurResFile(),
- GetResFileAttrs(index) | mapChanged);
- UpdateResFile(CurResFile());
- ReleaseResource(dataHandle);
- }
- if(drvrInstFlags & thinkMultSeg)
- ReleaseDrvrSegments(dcodHList, rsrcID, false);
- DisposHandle(drvrHandle);
- return(dInstErr);
- }
-
- /* Move the important information to the driver entry */
- ctlEntryPtr = *UTableBase[unitNum];
- drvrPtr = *(DriverHandle)drvrHandle;
- ctlEntryPtr->dCtlDriver = (Ptr)drvrHandle;
- ctlEntryPtr->dCtlFlags = drvrPtr->drvrFlags;
- ctlEntryPtr->dCtlDelay = drvrPtr->drvrDelay;
- ctlEntryPtr->dCtlEMask = drvrPtr->drvrEMask;
- ctlEntryPtr->dCtlMenu = drvrPtr->drvrMenu;
- ctlEntryPtr->dCtlFlags |= dRAMBased;
-
- /* Hang onto the refNum just in case open changes it. */
- index = CurResFile();
-
- /*
- * The open routine better load all the DATA and DCOD resources. If
- * the driver is going to want to be closed, it should store what
- * is passed to it in ioMisc and pass it back when close is called.
- */
- if(drvrInstFlags & open) {
- openBlock.ioCompletion = nil;
- openBlock.ioNamePtr = drvrName;
- openBlock.ioPermssn = fsCurPerm;
- openBlock.ioMisc = (Ptr)dcodHList;
- errCode = PBOpen(&openBlock, false);
- }
-
- /* Change CurResFile back to our original one. */
- UseResFile(index);
-
- if(drvrInstFlags & thinkDATA) {
- /*
- * If the open was successful, the dataHandle will be detached.
- * If the open failed, dataHandle may or may not be an attached
- * resource, but probably isn't attached. Therefore, the resource
- * must be retrieved to change the resource ID back, just in case
- * the open routine changed the file's resource map. After that,
- * release it. Errors here will be horrific because the file will
- * basically be corrupted if the ID can't be changed back, so
- * don't bother checking. At this point in the game, errors
- * shouldn't occur anyway.
- */
- SetResLoad(false);
- dataHandle = Get1Resource('DATA', (unitNum << 5) | 0xC000);
- SetResLoad(true);
- if(dataHandle != nil) {
- SetResInfo(dataHandle, (rsrcID << 5) | 0xC000, 0);
- SetResFileAttrs(CurResFile(),
- GetResFileAttrs(index) | mapChanged);
- UpdateResFile(CurResFile());
- ReleaseResource(dataHandle);
- }
- }
-
- /* If an error occurred during the open */
- if(errCode != noErr) {
- RemoveRAMDriver(~unitNum, false);
- if(drvrInstFlags & thinkMultSeg)
- ReleaseDrvrSegments(dcodHList, rsrcID, false);
- } else {
- ReleaseDrvrSegments(dcodHList, rsrcID, true);
- *refNum = ~unitNum;
- }
- return(errCode);
- }
-
- /*
- * Removes the driver installed in the system heap by InstallRAMDriver.
- * See the warning on InstallRAMDriver about the ioMisc field.
- */
-
- OSErr RemoveRAMDriver(short refNum, Boolean dcodRemove)
- {
- OSErr errCode = noErr, dcodHandles, index;
- Handle dataHandle = nil, *dcodHList = nil, drvrHandle;
- ioParam closeBlock;
-
- /* If the driver is open, close it */
- if((**UTableBase[~refNum]).dCtlFlags & dOpened) {
- closeBlock.ioCompletion = nil;
- closeBlock.ioRefNum = refNum;
- errCode = PBClose(&closeBlock, false);
- if(errCode != noErr)
- return(errCode);
- dcodHList = (Handle *)closeBlock.ioMisc;
- dataHandle = (Handle)(**UTableBase[~refNum]).dCtlStorage;
- }
-
- /*
- * Since the driver has been detached, it will have to be disposed of
- * later since DrvrRemove just does a ReleaseResource on the handle.
- */
- drvrHandle = (Handle)(**UTableBase[~refNum]).dCtlDriver;
- errCode = DrvrRemove(refNum);
- if(errCode != noErr)
- return(errCode);
- if(drvrHandle != nil) {
- DisposHandle(drvrHandle);
- if(dcodRemove && (dcodHList != nil)) {
-
- /* The driver has passed back the handles to its segments so
- * they can be disposed of.
- */
- dcodHandles = GetPtrSize(&dcodHList) / sizeof(Handle);
- for(index = 0; index < dcodHandles; ++index)
- DisposHandle(dcodHList[index]);
- DisposPtr(dcodHList);
- }
- }
- return(noErr);
- }
-
- short GetDrvrRefNum(Str255 drvrName)
- {
- short unitNum;
- DCtlHandle curDCtlEntry;
- DriverPtr curDrvrPtr;
-
- /* Walk through the Unit Table */
- for(unitNum = 0; unitNum < UnitNtryCnt; ++unitNum) {
- curDCtlEntry = GetDCtlEntry(~unitNum);
- if(curDCtlEntry != nil) {
-
- /* If this is a RAM driver, it's a handle. ROM is a pointer */
- if((**curDCtlEntry).dCtlFlags & dRAMBased)
- curDrvrPtr = *(DriverHandle)(**curDCtlEntry).dCtlDriver;
- else
- curDrvrPtr = (DriverPtr)(**curDCtlEntry).dCtlDriver;
-
- /* Does the driver name match? */
- if(curDrvrPtr != nil)
- if(EqualString(drvrName, curDrvrPtr->drvrName,
- false, false))
- return(~unitNum);
- }
- }
- return(0);
- }
-
- OSErr GrowUTable(short newEntries)
- {
- DCtlHandle *newUTableBase;
-
- /* Make room for the new Unit Table */
- newUTableBase = (DCtlHandle *)NewPtrSysClear((UnitNtryCnt + newEntries)
- * sizeof(DCtlHandle));
- if(MemError() != noErr)
- return(MemError());
- asm {
- MOVE SR,-(SP) ; Save status register
- MOVE #SCCLockOut,SR ; Disable interrupts
- }
-
- /* Move the old Unit Table to the new Unit Table */
- BlockMove(UTableBase, newUTableBase, UnitNtryCnt * sizeof(DCtlHandle));
- DisposPtr(UTableBase);
- UTableBase = newUTableBase;
- UnitNtryCnt += newEntries;
- asm {
- MOVE (SP)+,SR ; Restore status register
- }
- return(noErr);
- }
-
- OSErr DriverAvail(short *unitNum)
- {
- short unitIndex;
- Size UTableSize;
- OSErr errCode = noErr;
-
- *unitNum = 0;
-
- /* Increase Unit Table size for Mac Plus */
- if(UnitNtryCnt <= LOW_UNIT)
- errCode = GrowUTable(NEW_UNIT - UnitNtryCnt);
- if(errCode != noErr)
- return(errCode);
-
- /* Look for an empty slot in what's already there */
- for(unitIndex = LOW_UNIT;
- (unitIndex < UnitNtryCnt) && (*unitNum == 0);
- ++unitIndex)
- if(UTableBase[unitIndex] == nil)
- *unitNum = unitIndex;
-
- /* Unit Table full up to UnitNtryCnt, so increase it */
- if(*unitNum == 0) {
- UTableSize = GetPtrSize(UTableBase) / sizeof(DCtlHandle);
-
- /* If there is space in the Unit Table, just up the count */
- if(UTableSize > UnitNtryCnt) {
- *unitNum = UnitNtryCnt;
- UnitNtryCnt += (UTableSize - UnitNtryCnt < UP_UNIT
- ? UTableSize - UnitNtryCnt
- : UP_UNIT);
-
- /* If there isn't enough space, try to increase it */
- } else {
- if(MAX_UNIT - UnitNtryCnt != 0) {
- unitIndex = UnitNtryCnt;
- errCode = GrowUTable(MAX_UNIT - UnitNtryCnt < UP_UNIT
- ? MAX_UNIT - UnitNtryCnt
- : UP_UNIT);
- if(errCode != noErr)
- return(errCode);
- *unitNum = unitIndex;
- }
- }
- }
- if(*unitNum == 0)
- return(unitTblFullErr);
- else
- return(noErr);
- }
-
- void ReleaseDrvrSegments(Handle *dcodHList, short rsrcID, Boolean detach)
- {
- short index, dcodHandles, dcodRsrcID;
- long rsrcType;
- Str255 rsrcName;
-
- dcodHandles = GetPtrSize(&dcodHList) / sizeof(Handle);
- if(rsrcID != 0) {
- for(index = 0; index < dcodHandles; ++index)
- if(dcodHList[index]) {
- GetResInfo(dcodHList[index], &dcodRsrcID,
- &rsrcType, &rsrcName);
- SetResInfo(dcodHList[index],
- (dcodRsrcID & 0xF01F) + (rsrcID << 5),
- 0);
- }
- SetResFileAttrs(CurResFile(), GetResFileAttrs(index) | mapChanged);
- UpdateResFile(CurResFile());
- }
- for(index = 0; index < dcodHandles; ++index)
- if(dcodHList[index]) {
- if(detach)
- DetachResource(dcodHList[index]);
- else
- ReleaseResource(dcodHList[index]);
- }
- if(!detach)
- DisposPtr(dcodHList);
- }
-